﻿#pragma once
#include "pch.h"

///----
static inline int judge_equeal(const char* pos, const char* compare, size_t& clen)
{
	for (size_t i = 0; i < clen; i++)
	{
		if (pos[i] != compare[i])
			return -1;
	}
	return 0;
}
static inline int string_find(const char* u, const char* compare)
{
	size_t clen = strlen(compare);
	size_t ulen = strlen(u);
	if (clen > ulen)
		return -1;
	const char* pos = u;
	const char* posend = u + ulen - 1;
	for (; pos <= posend - clen; pos++)
	{
		if (judge_equeal(pos, compare, clen) == 0)
		{
			return (int)(pos - u);
			//return 0;
		}
	}
	return -1;
}
static inline const char* string_find_pos(const char* u, const char* compare)
{
	size_t clen = strlen(compare);
	size_t ulen = strlen(u);
	if (clen > ulen)
		return NULL;
	const char* pos = u;
	const char* posend = u + ulen - 1;
	for (; pos <= posend - clen; pos++)
	{
		if (judge_equeal(pos, compare, clen) == 0)
		{
			return pos;
			//return 0;
		}
	}
	return NULL;
}
typedef struct UrlParam
{
	std::string protocol;
	std::string host;
	unsigned short port = 80;
	std::string uri;
	std::map<std::string, std::string> uri_map;
	void clear()
	{
		protocol.clear();
		host.clear();
		uri.clear();
		uri_map.clear();
		port = 80;
	}
}TUrlParam;



class WoHTTPParseUrl
{
protected:
	static int parse_domain(const char* pos, const char* posend, TUrlParam& param)
	{
		int point = string_find(pos, ":");
		if (point >= 0)
		{
			param.host = std::string(pos, point);
			pos += point + 1;
			std::string tmp = std::string(pos, posend - pos);
			if (IsNumber(tmp.c_str()))
				param.port = atoi(tmp.c_str());
			return 0;
		}
		return -1;
	}
	static bool IsNumber(const char* num)
	{
		int length = (int)strlen(num);
		for (int i = 0; i < length; i++)
		{
			if (i == 0 && (num[i] == '+' || num[i] == '-'))
			{
				if (length > 1)
					continue;
				return false;
			}
			if (!isdigit(num[i]))
				return false;
		}
		return true;
	}
public:
	WoHTTPParseUrl() {}
	WoHTTPParseUrl(const char* url) {
		ParseUrl(url, v_param);
	}
	virtual ~WoHTTPParseUrl() {};
	TUrlParam v_param;

#define POS_JUDGE if(pos>=posend) return -1
#define POS_JUDGE_OK if(pos>=posend) return 0
	static int ParseUrl(const char* url, TUrlParam& param)
	{
		//memset(&param, 0, sizeof(param));
		const char* posend = url + strlen(url) - 1;
		param.uri = url;
		const char* pos = url;
		int point = 0;
		if ((point = string_find(pos, "://")) >= 0)
		{
			param.protocol = std::string(url, point);
		}
		else
			return -1;
		pos += point + 3; //strlen("://")
		POS_JUDGE;
		if ((point = string_find(pos, "/")) >= 0)
		{
			param.host = std::string(pos, point);
			const char* end = pos + point;
			parse_domain(pos, end, param);
			param.uri = std::string(pos + point + 1);
		}
		else
		{
			//the left all is domain
			int hlen = (int)(posend - pos + 1);
			param.host = std::string(pos, hlen);
			const char* end = pos + hlen - 1;
			parse_domain(pos, end, param);
			param.uri = "/";
			return 0;
		}
		const char* start = string_find_pos(param.uri.c_str(), "?");
		if (start==nullptr) {
			return 0;
		}
		std::vector<std::string> list;
		WoHaperStringSplitWithStlA_view(start+(1), "&", list);
		for (std::string_view str : list) {
			if (str == "" || str == "=") { continue; }
			std::vector<std::string> maps;
			WoHaperStringSplitWithStlA_view(str, "=", maps);
			if (maps.size() < 2) { continue; }
			param.uri_map[maps[0].c_str()] = maps[1].c_str();
		}
		return 0;
	}

	std::string GetParam(const char* param)
	{
		auto iter = v_param.uri_map.find(param);
		if (iter == v_param.uri_map.end()) {
			return "";
		}
		return iter->second;
		//int point = -1;
		//const char* ustart = v_param.uri.c_str();

		//const char* start = string_find_pos(ustart, "?");
		//if (start != NULL)
		//{
		//	++start;
		//	//?a=abc&b=ddd
		//	std::string par = param;
		//	par += "=";
		//	start = string_find_pos(start, par.c_str());
		//	if (start != NULL)
		//	{
		//		const char* j = start - 1;
		//		char c = *j;
		//		if (c == '&' || c == '?')
		//		{
		//			start += par.length();
		//			const char* end = string_find_pos(start, "&");
		//			if (end != NULL)
		//			{
		//				return std::string(start, end);
		//			}
		//			return std::string(start);
		//		}
		//	}
		//}
		//return "";
	}

	void SetUrl(const char* url)
	{
		v_param.clear();
		ParseUrl(url, v_param);
	}
};

///----




